package com.gframework.mybatis.dao;

import java.util.Collection;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

import com.gframework.mybatis.dao.mybatis.provider.ProviderUtils;
import com.gframework.sqlparam.BeanSqlParam;

/**
 * dao部分方法代理类.
 * <p>目前代理了默认提供的save和update方法，这两类方法本质上都是基于pojo进行处理操作，所以可以使用
 * {@link DaoSaveInterceptor} 和 {@link DaoUpdateInterceptor} 两个拦截器进行拦截处理操作。
 * <p>如果你的需求是对部分属性进行自动设置值，或者自动设置id，那么可以使用已经提供好的一个默认类 {@link AutoSetFieldDaoInterceptor}，只需要创建一个此类bean加入spring bean容器即可生效。
 * 
 * @since 2.0.0
 * @author Ghwolf
 * 
 * @see AutoSetFieldDaoInterceptor
 */
@Configuration(proxyBeanMethods = false)
public class DaoMethodAspect {

	@Bean
	@ConditionalOnBean(DaoSaveInterceptor.class)
	public DaoSaveMethodAspect getDaoSaveMethodAspect() {
		return new DaoSaveMethodAspect();
	}

	@Bean
	@ConditionalOnBean(DaoUpdateInterceptor.class)
	public DaoUpdateMethodAspect getDaoUpdateMethodAspect() {
		return new DaoUpdateMethodAspect();
	}

	/**
	 * 保存方法拦截器
	 */
	@Aspect
	@Order(Integer.MIN_VALUE + 10000)
	class DaoSaveMethodAspect {

		@Autowired
		private DaoSaveInterceptor[] daoSaveInterceptors;

		@Before("execution(* com.gframework.mybatis.dao.ITableBasicDAO+.save*(java.io.Serializable+))")
		public void save(JoinPoint point) {
			Object obj = point.getArgs()[0];
			if (obj == null) {
				return;
			}
			Class<?> pojoType = ProviderUtils.getMybatisDaoInfo(MybatisDaoAop.getDaoClass()).getPojoType();

			for (DaoSaveInterceptor inter : daoSaveInterceptors) {
				if (inter.canInterceptSave(pojoType)) {
					inter.interceptSave(pojoType,obj);
				}
			}
		}

		@Before("execution(* com.gframework.mybatis.dao.ITableBasicDAO+.save*(java.util.Collection<java.io.Serializable+>))")
		public void saveBatch(JoinPoint point) {
			Collection<?> obj = (Collection<?>) point.getArgs()[0];
			if (obj == null || obj.isEmpty()) {
				return;
			}
			Class<?> pojoType = ProviderUtils.getMybatisDaoInfo(MybatisDaoAop.getDaoClass()).getPojoType();

			for (DaoSaveInterceptor inter : daoSaveInterceptors) {
				if (inter.canInterceptSave(pojoType)) {
					for (Object o : obj) {
						if (o != null) {
							inter.interceptSave(pojoType,o);
						}
					}
				}
			}
		}

	}

	/**
	 * 修改方法拦截器
	 */
	@Aspect
	@Order(Integer.MIN_VALUE + 10000)
	class DaoUpdateMethodAspect {

		@Autowired
		private DaoUpdateInterceptor[] daoUpdateInterceptors;

		@Before("execution(* com.gframework.mybatis.dao.ITableBasicDAO+.update*(com.gframework.sqlparam.BeanSqlParam))")
		public void update(JoinPoint point) {
			BeanSqlParam<?> bsp = (BeanSqlParam<?>) point.getArgs()[0];
			if (bsp == null || bsp.getPojo() == null) {
				return;
			}
			Class<?> pojoType = ProviderUtils.getMybatisDaoInfo(MybatisDaoAop.getDaoClass()).getPojoType();

			for (DaoUpdateInterceptor inter : daoUpdateInterceptors) {
				if (inter.canInterceptUpdate(pojoType)) {
					inter.interceptUpdate(pojoType,bsp.getPojo());
				}
			}
		}

		@Before("execution(* com.gframework.mybatis.dao.IPrimaryDAO+.update*(java.io.Serializable+))")
		public void updateById(JoinPoint point) {
			Object obj = point.getArgs()[0];
			if (obj == null) {
				return;
			}
			Class<?> pojoType = ProviderUtils.getMybatisDaoInfo(MybatisDaoAop.getDaoClass()).getPojoType();

			for (DaoUpdateInterceptor inter : daoUpdateInterceptors) {
				if (inter.canInterceptUpdate(pojoType)) {
					inter.interceptUpdate(pojoType,obj);
				}
			}
		}

	}

}
